package com.tbit.uqbike.service.business.tag.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.tbit.config.datasource.DataSource;
import com.tbit.uqbike.enums.TagStatus;
import com.tbit.uqbike.object.pojo.tag.Tag;
import com.tbit.uqbike.object.pojo.vo.BatchOperationMsgVO;
import com.tbit.common.entity.view.PageResult;
import com.tbit.uqbike.service.base.RedisService;
import com.tbit.uqbike.service.business.tag.TagNameAlreadyExistsException;
import com.tbit.uqbike.service.business.tag.TagNotFoundException;
import com.tbit.uqbike.service.business.tag.TagService;
import com.tbit.uqbike.webmanager.dao.core.tag.TagDao;
import com.tbit.uqbike.webmanager.dto.TagDTO;
import com.tbit.uqbike.webmanager.req.tag.QueryTagListReq;
import com.tbit.uqbike.webmanager.resp.tag.TagBaseInfo;
import com.tbit.uqbike.webmanager.resp.tag.TagResp;
import com.tbit.uqbike.webmanager.util.DbOperationUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 标签服务实现
 *
 *
 * @author <a href="mailto:chen.chaoxiong@tbit.com.cn">ChenChaoXiong</a>
 * @since 2024/7/8
 */
@Service
public class TagServiceImpl implements TagService {
    public static final String DISPATCH_CURR_TAG_KEY = "maintainPerformance:dispatch:tag:";

    @Resource
    private TagDao tagDao;

    @Autowired
    private ApplicationContext context;

    @Autowired
    RedisService redisService;

    //自引用
    private TagService self;


    @PostConstruct
    private void initSelf() {
        //不适合于prototype Bean，因为每次getBean返回一个新的Bean
        self = context.getBean(TagService.class);
    }


    @Override
    public Long createTag(TagDTO tagDTO) throws TagNameAlreadyExistsException {
        Tag tag = tagDTO.toCreateTag();
        tag.setCreateTime(LocalDateTime.now());
        tag.setUpdateTime(LocalDateTime.now());
        validateTagNameUniqueness(tagDTO.getBrandId(), tagDTO.getTagName());
        return saveTag(tag);
    }

    @Override
    public Boolean updateTag(TagDTO tagDTO) throws TagNameAlreadyExistsException, TagNotFoundException {
        Tag existingTag = tagDao.selectById(tagDTO.getId());
        if (existingTag == null) {
            throw new TagNotFoundException("Tag with ID " + tagDTO.getId() + " not found");
        }

        boolean nameUpdated = updateTagName(existingTag, tagDTO.getTagName());
        if (nameUpdated) {
            validateTagNameUniqueness(existingTag.getBrandId(), existingTag.getName());
        }
        boolean statusUpdated = updateTagStatus(existingTag, tagDTO.getTagStatus());

        //如果标签名称或状态有更新，则更新
        if (nameUpdated || statusUpdated) {
            if (statusUpdated){
                existingTag.setTagStatus(tagDTO.getTagStatus());
            }
            existingTag.setUpdateTime(LocalDateTime.now());
            existingTag.setOperatorId(tagDTO.getUserInfo().getAccountUserId());
            return DbOperationUtil.isSuccess(tagDao.update(existingTag));
        }
        return false;
    }

    private boolean updateTagName(Tag existingTag, String newTagName) {
        if (!existingTag.getName().equals(newTagName)) {
            existingTag.setName(newTagName);
            return true;
        }
        return false;
    }

    private boolean updateTagStatus(Tag existingTag, TagStatus newStatus) {
        return !Objects.equals(existingTag.getTagStatus(), newStatus);
    }


    @Override
    public BatchOperationMsgVO<String> deleteTagBatch(List<TagDTO> tags) {
        BatchOperationMsgVO<String> batchOperationMsgVO = new BatchOperationMsgVO<>();
        tags.forEach(tag -> {
            if (self.deleteTag(tag)) {
                batchOperationMsgVO.putSuccessValue(tag.getId().toString());
            } else {
                batchOperationMsgVO.putFailValue(tag.getId().toString());
            }
        });
        return batchOperationMsgVO;
    }

    @Override
    public BatchOperationMsgVO<String> enableBatch(List<TagDTO> tags) {
        BatchOperationMsgVO<String> batchOperationMsgVO = new BatchOperationMsgVO<>();
        tags.forEach(tag -> {
           if (enableTag(tag)) {
               batchOperationMsgVO.putSuccessValue(tag.getId().toString());
           } else {
               batchOperationMsgVO.putFailValue(tag.getId().toString());
           }
        });
        return batchOperationMsgVO;
    }

    
    private Boolean enableTag(TagDTO tag) {
        //只能从禁用状态启用
        List<Integer> expectedStatus = Arrays.asList(TagStatus.DISABLED.getValue());
        return DbOperationUtil.isSuccess(tagDao.updateStatus(tag.getId(), TagStatus.ENABLED.getValue(),expectedStatus));
    }

    @Override
    public Boolean disableTag(TagDTO tag) {
        //只能从启用状态禁用
        List<Integer> expectedStatus = Arrays.asList(TagStatus.ENABLED.getValue());
        return DbOperationUtil.isSuccess(tagDao.updateStatus(tag.getId(), TagStatus.DISABLED.getValue(),expectedStatus));
    }

    @Override
    public Boolean deleteTag(TagDTO tag) {
        //只能从启用或禁用状态删除
        List<Integer> expectedStatus = Arrays.asList(TagStatus.ENABLED.getValue(),TagStatus.DISABLED.getValue());
        return DbOperationUtil.isSuccess(tagDao.updateStatus(tag.getId(), TagStatus.DELETED.getValue(),expectedStatus));
    }

    @Override
    public BatchOperationMsgVO<String>  disableBatch(List<TagDTO> tags) {
        BatchOperationMsgVO<String> batchOperationMsgVO = new BatchOperationMsgVO<>();
        tags.forEach(tag -> {
            if (self.disableTag(tag)) {
                batchOperationMsgVO.putSuccessValue(tag.getId().toString());
            } else {
                batchOperationMsgVO.putFailValue(tag.getId().toString());
            }
        });
        return batchOperationMsgVO;
    }

    @Override
    public List<TagBaseInfo> list(Integer brandId, TagStatus tagStatus) {
        return tagDao.selectList(brandId,tagStatus);
    }

    @Override
    public PageResult<List<TagResp>> listPage(QueryTagListReq req) {
        Integer page = req.getPage();
        Integer size = req.getRowCount();
        PageInfo<List<TagResp>> pageInfo = PageHelper.startPage(page, size).doSelectPageInfo(() -> tagDao.selectListPage(req));
        return new PageResult<>(page, size, pageInfo.getTotal(), pageInfo.getPages(), pageInfo.getList());
    }

    @Override
    public Set<Long> extractEnableTagIds(Set<Long> tagIds) {
        if (CollectionUtil.isEmpty(tagIds)) {
            return new HashSet<>();
        }
        Set<Long> existList = Optional.ofNullable(tagDao.selectEnableIds(tagIds))
                .map(HashSet::new)
                .orElse(new HashSet<>());
        existList.forEach(tagIds::remove);
        return tagIds;
    }

    private boolean isTagNameUnique(Integer brandId,String tagName) {
        return Objects.isNull(tagDao.selectByBrandIdAndName(brandId, tagName));
    }

    private void validateTagNameUniqueness(Integer brandId, String tagName) {
        boolean isUnique = isTagNameUnique(brandId, tagName);
        if (!isUnique) {
            throw new TagNameAlreadyExistsException("标签名称重复");
        }
    }

    private Long saveTag(Tag tag) {
        tagDao.insert(tag);
        return tag.getId();
    }

    @Override
    public List<Tag> getTags(Integer machineId) {
        String ids = redisService.get(DISPATCH_CURR_TAG_KEY + machineId);
        if (ids == null) {
            return Collections.emptyList();
        }
        Set<Long> idSet = Arrays.stream(ids.split(","))
                .map(Long::parseLong)
                .collect(Collectors.toSet());
        return tagDao.selectByIds(idSet);
    }
}
